//
//  NSDate+Lc.m
//  18Birdies
//
//  Created by Lc on 15/4/6.
//  Copyright (c) 2015年 Lc. All rights reserved.
//

#include <sys/sysctl.h>
#import "LcPreconditions.h"
#import "NSDate+Lc.h"
#import "NSCalendar+Lc.h"

NSString* const TIMEFORMAT_STANDARD = @"M/d/yyyy hh:mm a";
NSString* const TIMEFORMAT_STANDARD_DESC = @"hh:mm a, M/d/yyyy";
NSString* const TIMEFORMAT_STANDARD_YYTIME = @"yyyy, hh:mm a";
NSString* const TIMEFORMAT_STANDARD_DAY = @"M/d/yyyy";
NSString* const TIMEFORMAT_STANDARD_MMDDYYYY = @"MM/dd/yyyy";
NSString* const TIMEFORMAT_STANDARD_MMDDYY = @"MM/dd/yy";
NSString* const TIMEFORMAT_STANDARD_MMDDYY_THUMB = @"M/d/yy";
NSString* const TIMEFORMAT_STANDARD_TIME = @"hh:mm a";
NSString* const TIMEFORMAT_WEATHER_MAP_TIME = @"'Map Time:'EEE MMM dd yyyy hh:mm a";

@implementation NSDate (Lc)

+ (NSDate*)dateFromTimeMillis:(long long)timeMillis {
  return [NSDate dateWithTimeIntervalSince1970:timeMillis / 1000.0];
}

- (BOOL)isDateWillBeExpiredInOneMonth {
  long long expiredTimeMillis = self.timeMillis;
  long long currentTimeMillis = NSDate.currentTimeMillis;
  long long gapTimeMillis = expiredTimeMillis - currentTimeMillis;
  LC_CHECK_TRUE(gapTimeMillis > 0);
  return gapTimeMillis < (long long)ONE_DAY_MS * 30;
}

+ (long long)currentTimeMillis {
  return [[self date] timeMillis];
}

+ (long long)serverTimeMillis {
  return [[[self class] nowServerTime] timeMillis];
}

+ (long long)upTimeMillis {
  struct timeval bootTime;
  int mib[2] = {CTL_KERN, KERN_BOOTTIME};
  size_t size = sizeof(bootTime);
  time_t now;
  time(&now);
  if (sysctl(mib, 2, &bootTime, &size, NULL, 0) != -1) {
    return ((long long)(now - bootTime.tv_sec)) * 1000L;
  }
  LC_DEBUG_FAIL();
  return 0L;
}

- (long long)timeMillis {
  return (long long)([self timeIntervalSince1970] * 1000L);
}

+ (NSDate*)nowServerTime {
  return [NSDate dateFromTimeMillis:[NSDate currentTimeMillis]];
}

- (NSString*)toStringWithFormat:(NSString*)format {
  NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
  [dateFormatter setDateFormat:format];
  NSString* destDateString = [dateFormatter stringFromDate:self];
  return destDateString;
}

- (NSString*)toStringWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone {
  NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
  if (timeZone != nil) {
    dateFormatter.timeZone = timeZone;
  }
  [dateFormatter setDateFormat:format];
  NSString* destDateString = [dateFormatter stringFromDate:self];
  return destDateString;
}

- (NSString*)toStringWithFormat:(NSString*)format timeZoneId:(NSString*)timeZoneId {
  NSTimeZone* timeZone = nil;
  if (timeZoneId.length > 0) {
    timeZone = [NSTimeZone timeZoneWithName:timeZoneId];
  }
  return [self toStringWithFormat:format timeZone:timeZone];
}

- (BOOL)isSameDayWithDate:(NSDate*)anotherDate {
  return [self isSameDayWithDate:anotherDate timeZone:nil];
}

- (BOOL)isSameDayWithDate:(NSDate*)anotherDate timeZoneId:(NSString*)timeZoneId {
  NSTimeZone* timeZone = nil;
  if (timeZoneId.length > 0) {
    timeZone = [NSTimeZone timeZoneWithName:timeZoneId];
  }
  return [self isSameDayWithDate:anotherDate timeZone:timeZone];
}

- (BOOL)isSameDayWithDate:(NSDate*)anotherDate timeZone:(NSTimeZone*)timeZone {
  NSCalendar* calendar = [NSCalendar sharedCalendar];
  if (timeZone != nil) {
    calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    calendar.timeZone = timeZone;
  }
  NSDateComponents* comp1 = [calendar components:CALENDARUNIT_STANDARD_DAY fromDate:self];
  NSDateComponents* comp2 = [calendar components:CALENDARUNIT_STANDARD_DAY fromDate:anotherDate];
  return comp1.day == comp2.day && comp1.month == comp2.month && comp1.year == comp2.year;
}

+ (NSDate*)dateFromString:(NSString*)dateString andFormat:(NSString*)format {
  return [self dateFromString:dateString andFormat:format timeZone:nil];
}

+ (NSDate*)dateFromString:(NSString*)dateString
                andFormat:(NSString*)format
                 timeZone:(NSTimeZone*)timeZone {
  NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
  [dateFormatter setDateFormat:format];
  if (timeZone != nil) {
    dateFormatter.timeZone = timeZone;
  }
  return [dateFormatter dateFromString:dateString];
}

+ (NSDate*)dateFromString:(NSString*)dateString
                andFormat:(NSString*)format
               timeZoneId:(NSString*)timeZoneId {
  NSTimeZone* timeZone = nil;
  if (timeZoneId.length > 0) {
    timeZone = [NSTimeZone timeZoneWithName:timeZoneId];
  }
  return [self dateFromString:dateString andFormat:format timeZone:timeZone];
}

- (NSString*)standardFormatString {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD];
}
- (NSString*)standardFormatString_desc {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_DESC];
}

- (NSString*)standardFormatYYTIMEString {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_YYTIME];
}

- (NSString*)standardMMDDYYYYFormatString {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_MMDDYYYY];
}

- (NSString*)standardMMDDYYFormatString {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_MMDDYY];
}

- (NSString*)standardMMDDYYThumbFormatStringWithTimeZone:(NSTimeZone*)timeZone {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_MMDDYY_THUMB timeZone:timeZone];
}

- (NSString*)standardMMDDYYThumbFormatStringWithTimeZoneId:(NSString*)timeZoneId {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_MMDDYY_THUMB timeZoneId:timeZoneId];
}

- (NSString*)standardDayFormatString {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_DAY];
}

- (NSString*)standardDayThumbFormatString {
  return [self toStringWithFormat:TIMEFORMAT_STANDARD_MMDDYY_THUMB];
}

- (NSString*)weatherMapTimeString {
  NSString* strF = [self toStringWithFormat:TIMEFORMAT_WEATHER_MAP_TIME];
  NSString* strS = [self toStringWithFormat:@" ZZZZ"];
  return [strF stringByAppendingString:strS];
}

- (NSString*)autoStandardDayFormatString {
  if ([self isSameDayWithDate:[NSDate nowServerTime]]) {
    return [self toStringWithFormat:TIMEFORMAT_STANDARD_TIME];
  } else {
    return [self toStringWithFormat:TIMEFORMAT_STANDARD_DAY];
  }
}

- (NSString*)timeLeftString {
  NSDate* nowDate = [NSDate nowServerTime];
  long long timeSecondsDiff = [self timeIntervalSince1970] - [nowDate timeIntervalSince1970];
  long long oneDaySeconds = ONE_DAY_MS / 1000;
  long long oneHourSeconds = ONE_HOUR_MS / 1000;
  long long oneMinuteSeconds = ONE_MINUTE_MS / 1000;
  if (timeSecondsDiff <= 0L) {
    return @"";
  } else if (timeSecondsDiff < oneDaySeconds) {
    // left time less than 24h
    long long hour = timeSecondsDiff / oneHourSeconds;
    long long minute = (timeSecondsDiff % oneHourSeconds) / oneMinuteSeconds;
    long long second = timeSecondsDiff % oneMinuteSeconds;
    return [NSString stringWithFormat:@"%02lld:%02lld:%02lld", hour, minute, second];
  } else {
    long long daysLeft = timeSecondsDiff / oneDaySeconds;
    if (daysLeft == 1) {
      return @"1 day";
    } else {
      return [NSString stringWithFormat:@"%lld days", daysLeft];
    }
  }
}

+ (NSString*)weekDay:(long long)temstamp {
  //[NSNull null] 占位 components.weekday最小从1（sunday）开始；
  // calendar.firstWeekday可以设置每周从第几天开始
  NSArray* weekday = [NSArray
      arrayWithObjects:[NSNull null], @"Sun", @"Mon", @"Tue", @"Wed", @"Thu", @"Fri", @"Sat", nil];
  NSDate* newDate = [self dateFromTimeMillis:temstamp];
  NSCalendar* calendar =
      [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  NSDateComponents* components = [calendar components:NSCalendarUnitWeekday fromDate:newDate];
  return [weekday objectAtIndex:components.weekday];
}

+ (NSString*)month:(long long)temstamp {
  //[NSNull null], @"January", @"February", @"March", @"April", @"May", @"June",@"July", @"August",
  //@"September", @"October", @"November", @"December", nil]
  NSArray* monthday =
      [NSArray arrayWithObjects:[NSNull null], @"Jan", @"Feb", @"Mar", @"Apr", @"May", @"Jun",
                                @"Jul", @"Aug", @"Sep", @"Oct", @"Nov", @"Dec", nil];
  NSDate* newDate = [self dateFromTimeMillis:temstamp];
  NSCalendar* calendar =
      [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  NSDateComponents* components = [calendar components:NSCalendarUnitMonth fromDate:newDate];
  return [monthday objectAtIndex:components.month];
}

+ (NSString*)day:(long long)temstamp {
  NSDate* newDate = [self dateFromTimeMillis:temstamp];
  NSCalendar* calendar =
      [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
  NSDateComponents* components = [calendar components:NSCalendarUnitDay fromDate:newDate];
  return [NSString stringWithFormat:@"%d", (int)components.day];
}

+ (NSString*)monthDay:(long long)temstamp {
  return [NSString stringWithFormat:@"%@ %@", [self month:temstamp], [self day:temstamp]];
}

+ (NSString*)minWithDuration:(double)duration {
  double min = ceil(duration / 60.0);
  if (min > 0) {
    return [NSString stringWithFormat:@"%.0f min", min];
  }
  return @"";
}

@end

